#include "mbed.h"
#include "rtos.h"
#include "remoteupdate.h"
#include "flash25spi.h"
#include "userfirmwarepro.h"
#include "mbedtinydtls.h"

static uint16_t messageID;
static char deviceUniqId[25];
static char serverRequestCommandFlag = 0;
static char serverRequestCommand[32];
static char deviceRandomNum[32] = "__NULL";
static char lostConnectionFlag = 0;
GetUpdateinfo updateinfo;
GetSelfUpdateinfo selfUpdateinfo;

ServerRequestCommand parseServerRequestCommand(char *cmdStr) {
	if (strcmp(cmdStr, "update") == 0)
		return SERVER_REQUEST_UPDATE_COMMAND;
	else if (strcmp(cmdStr, "eval") == 0)
		return SERVER_REQUEST_EVAL_COMMAND;
	else if (strcmp(cmdStr, "random") == 0)
		return SERVER_REQUEST_RANDOM_COMMAND;
	else if (strcmp(cmdStr, "itemA") == 0)
		return SERVER_REQUEST_ITEMA_COMMAND;
	else if (strcmp(cmdStr, "itemB") == 0)
		return SERVER_REQUEST_ITEMB_COMMAND;
	else if (strcmp(cmdStr, "itemC") == 0)
		return SERVER_REQUEST_ITEMC_COMMAND;
	else if (strcmp(cmdStr, "itemD") == 0)
		return SERVER_REQUEST_ITEMD_COMMAND;
	else if (strcmp(cmdStr, "itemE") == 0)
		return SERVER_REQUEST_ITEME_COMMAND;
	else if (strcmp(cmdStr, "itemF") == 0)
		return SERVER_REQUEST_ITEMF_COMMAND;
	else if (strcmp(cmdStr, "configs") == 0)
		return SERVER_REQUEST_CONFIGS_COMMAND;
	else if (strcmp(cmdStr, "scanPorts") == 0)
		return SERVER_REQUEST_SCANPORTS_COMMAND;

	return SERVER_REQUEST_UNDEFINED_COMMAND;
}

int deviceRegister(int sockfd, char status) {
	MbedJSONValue json;
	char str[64] = {0};

	strncpy(str, header.devType, HDR_NAME_8CHAR_LEN);
	json["devType"] = str;

	memset(str, 0, sizeof(str));
	strncpy(str, header.softVerNo, HDR_NAME_12CHAR_LEN);
	json["softVerNo"] = str;

	memset(str, 0, sizeof(str));
	strncpy(str, header.hardVerNo, HDR_NAME_8CHAR_LEN);
	json["hardVerNo"] = str;

	memset(str, 0, sizeof(str));
	strncpy(str, header.firmwareNo, HDR_NAME_8CHAR_LEN);
	json["firmwareNo"] = str;

	json["mobile"] = "18888888888";
	json["devUniqId"] = (string)deviceUniqId;
	json["status"] =  status;

	if (header.userUpdateFileInfo[0] == 0 || header.userUpdateFileInfo[0] == 2) {
		char devType[32] = {0};
		char priVer[8] = {0};
		char secVer[8] = {0};
		char serNum[16] = {0};
		userfwpro userFWPro(&userCom);
		userFWPro.init();
		if (userFWPro.getUserVersion(devType, priVer, secVer, serNum) == 0) {
			json["userDevType"] = devType;
			json["userHardVerNo"] = priVer;
			json["userSoftVerNo"] = secVer;
			json["userBoardId"] = serNum;
			if (strcmp(devType, header.userDevType))
				updateUserDevType(devType);
			if (strcmp(priVer, header.userHardVerNo))
				updateUserHardVerNo(priVer);
			if (strcmp(secVer, header.userSoftVerNo))
				updateUserVersionNo(secVer);
		} else if (userFWPro.getUserIAPVersion() == 0){
				json["userDevType"] = "TheCut_IAP";
				json["userHardVerNo"] = "00";
				json["userSoftVerNo"] = "00";
				json["userBoardId"] = "00000000";
				json["status"] =  3;
		} else {
			json["userDevType"] = "Unknown";
			json["userHardVerNo"] = "00";
			json["userSoftVerNo"] = "00";
			json["userBoardId"] = "00000000";
		}
	} else {
		json["userDevType"] = "Unknown";
		json["userHardVerNo"] = "00";
		json["userSoftVerNo"] = "00";
		json["userBoardId"] = "00000000";
	}

	string jsonStr = json.serialize();
	printf("\r%s : [Packet sending] = %s\r\n" , __func__, jsonStr.c_str());

	char *payload = (char *)jsonStr.c_str();
    // construct CoAP packet
    CoapPDU *pdu = new CoapPDU();
    pdu->setVersion(1);
    pdu->setType(CoapPDU::COAP_CONFIRMABLE);
    pdu->setCode(CoapPDU::COAP_POST);
    pdu->setToken((uint8_t*)"\3\2\1\1",4);
	pdu->setURI((char*)"register", 8);
	pdu->setPayload((uint8_t*)payload,strlen(payload));

	char tryNum = 5;
	int ret = 0;

	// send packets to server
    do {
        // set PDU parameters
        pdu->setMessageID(++messageID);

        // send packet 
		ret = dtls_write(dtls_context, &g_dst, pdu->getPDUPointer(), pdu->getPDULength());
		if(ret!=pdu->getPDULength()) {
			INFO("Error sending packet.");
			pdu->reset();
			delete pdu;
			lostConnectionFlag = 1;
			NetLED_ticker.detach();
			NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
			return -2;
		}
//      INFO("Packet sent");

        // receive response
		do {
			char buffer[BUFLEN] = {0};
			session_t session;
			memset(&session, 0, sizeof(session_t));
			session.size = sizeof(session.addr);

			ret = recvfrom(sockfd, &buffer,BUFLEN,0, &session.addr.sa, &session.size);
			if(ret==-1) {
				INFO("Error receiving data");
				pdu->reset();
				delete pdu;
				lostConnectionFlag = 1;
				NetLED_ticker.detach();
				NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
				return -3;
			}
//			INFO("session address family: %d, size: %d",session.addr.sa.sa_family,session.size);
//			INFO("Received %d bytes from %s:%d",ret,inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port));
			if(ret > BUFLEN) {
				INFO("PDU too large to fit in pre-allocated buffer");
				tryNum--;
				break;
			} else if(ret > 0) {
				buffer[ret] = 0x00;
				#if __DEBUG__ > 0
				unsigned char addrbuf[72];
				dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
				DBG("Got %d bytes from %s", len, (char *)addrbuf);
				dump((unsigned char *)&session, sizeof(session_t));
				DBGX("\r\n");
				dump(buf, len);
				DBGX("\r\n");
				#endif
			}
//			INFO("Calling dtls_handle_message with context: %lx, session: %lx, buf: %lx, bytes: %d",
//				(unsigned long)dtls_context,(unsigned long)&session,(unsigned long)buffer, ret);
			dtls_handle_message(dtls_context, &session, (uint8_t*)buffer, ret);

			// reuse the below coap object
			CoapPDU *recvPDU = new CoapPDU(clearText, clearTextLen, clearTextLen);
			// validate packet
			recvPDU->setPDULength(clearTextLen);
			if(recvPDU->validate()!=1) {
				INFO("Malformed CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -4;
			}
#if 0
			INFO("Valid CoAP PDU received");
			recvPDU->printHuman();
#endif
			if (recvPDU->getMessageID() != messageID) {
				INFO("Unmatched CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				continue;
			}

			MbedJSONValue recvJson;
			parse(recvJson, (char *)recvPDU->getPayloadPointer());
			jsonStr = recvJson.serialize();
			printf("\r%s : [Packet receive] = %s\r\n" , __func__, jsonStr.c_str());
			if (recvJson.hasMember((char *)SUCCESS) && (recvJson[SUCCESS].get<bool>() ||
				strcmp(recvJson[MSG].get<string>().c_str(), ALREADY_REGISTERED) == 0)) {
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				if (lostConnectionFlag == 1) {
					lostConnectionFlag = 0;
					NetLED_ticker.detach();
					NetLED_ticker.attach(&toggle_NetLed, 0.5);	//net is again connect
				}
				return 0;
			} else {
				tryNum--;
				recvPDU->reset();
				delete recvPDU;
				break;
			}
		} while(true);

		Thread::wait(3000);
	} while (tryNum);

	pdu->reset();
	delete pdu;
	return -1;
}

int deviceStatusReport(int sockfd, char status) {
	MbedJSONValue json;
	json["devUniqId"] = (string)deviceUniqId;
	json["status"] =  status;

	time_t tt = time(0);
	char str[16];
	sprintf(str, "%u", tt);
	json["timestamp"] = str;

	string jsonStr = json.serialize();
	printf("\r%s : [Packet sending] = %s\r\n" , __func__, jsonStr.c_str());

	char *payload = (char *)jsonStr.c_str();
    // construct CoAP packet
    CoapPDU *pdu = new CoapPDU();
    pdu->setVersion(1);
    pdu->setType(CoapPDU::COAP_CONFIRMABLE);
    pdu->setCode(CoapPDU::COAP_POST);
    pdu->setToken((uint8_t*)"\3\2\1\1",4);
	pdu->setURI((char*)"deviceStatus", 12);
	pdu->setPayload((uint8_t*)payload,strlen(payload));

	char tryNum = 5;
	int ret = 0;
	// send packets to server
    do {
        // set PDU parameters
        pdu->setMessageID(++messageID);

		// send packet 
		ret = dtls_write(dtls_context, &g_dst, pdu->getPDUPointer(), pdu->getPDULength());
		if(ret!=pdu->getPDULength()) {
			INFO("Error sending packet.");
			pdu->reset();
			delete pdu;
			lostConnectionFlag = 1;
			NetLED_ticker.detach();
			NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
			return -2;
		}
//        INFO("Packet sent");

        // receive response
		do {
			char buffer[BUFLEN] = {0};
			session_t session;
			memset(&session, 0, sizeof(session_t));
			session.size = sizeof(session.addr);

			ret = recvfrom(sockfd, &buffer, BUFLEN, 0, &session.addr.sa, &session.size);
			if(ret==-1) {
				INFO("Error receiving data");
				pdu->reset();
				delete pdu;
				lostConnectionFlag = 1;
				NetLED_ticker.detach();
				NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
				return -3;
			}
//			INFO("session address family: %d, size: %d",session.addr.sa.sa_family,session.size);
//			INFO("Received %d bytes from %s:%d",ret,inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port));
			if(ret > BUFLEN) {
				INFO("PDU too large to fit in pre-allocated buffer");
				tryNum--;
				break;
			} else if(ret > 0) {
				buffer[ret] = 0x00;
				#if __DEBUG__ > 0
				unsigned char addrbuf[72];
				dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
				DBG("Got %d bytes from %s", len, (char *)addrbuf);
				dump((unsigned char *)&session, sizeof(session_t));
				DBGX("\r\n");
				dump(buf, len);
				DBGX("\r\n");
				#endif
			}
//			INFO("calling dtls_handle_message with context: %lx, session: %lx, buf: %lx, bytes: %d",
//				(unsigned long)dtls_context,(unsigned long)&session,(unsigned long)buffer, ret);
			dtls_handle_message(dtls_context, &session, (uint8_t*)buffer, ret);

			// reuse the below coap object
			CoapPDU *recvPDU = new CoapPDU(clearText, clearTextLen, clearTextLen);
			// validate packet
			recvPDU->setPDULength(clearTextLen);
			if(recvPDU->validate()!=1) {
				INFO("Malformed CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -4;
			}
#if 0
			INFO("Valid CoAP PDU received");
			recvPDU->printHuman();
#endif
			if (recvPDU->getMessageID() != messageID) {
				INFO("Unmatched CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				continue;
			}

			MbedJSONValue recvJson;
			parse(recvJson, (char *)recvPDU->getPayloadPointer());
			jsonStr = recvJson.serialize();
			printf("\r%s : [Packet receive] = %s\r\n" , __func__, jsonStr.c_str());
			if (recvJson.hasMember((char *)SUCCESS) && recvJson[SUCCESS].get<bool>()) {
				if (recvJson.hasMember((char *)COMMAND) &&
					strlen(recvJson[COMMAND].get<string>().c_str()) < sizeof(serverRequestCommand)) {
					serverRequestCommandFlag = 1;
					memset(serverRequestCommand, 0, sizeof(serverRequestCommand));
					strcpy(serverRequestCommand, recvJson[COMMAND].get<string>().c_str());
				}
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				if (lostConnectionFlag == 1) {
					lostConnectionFlag = 0;
					NetLED_ticker.detach();
					NetLED_ticker.attach(&toggle_NetLed, 0.5);	//net is again connect
				}
				return 0;
			} else {
				tryNum--;
				recvPDU->reset();
				delete recvPDU;
				break;
			}
		} while(true);

        Thread::wait(3000);
    } while (tryNum);
	
	pdu->reset();
	delete pdu;
	return -1;
}

int deviceGetUpdateinfo(int sockfd) {
	MbedJSONValue json;
	json["devUniqId"] = (string)deviceUniqId;

	string jsonStr = json.serialize();
	printf("\r%s : [Packet sending] = %s\r\n" , __func__, jsonStr.c_str());

	char *payload = (char *)jsonStr.c_str();
    // construct CoAP packet
    CoapPDU *pdu = new CoapPDU();
    pdu->setVersion(1);
    pdu->setType(CoapPDU::COAP_CONFIRMABLE);
    pdu->setCode(CoapPDU::COAP_POST);
    pdu->setToken((uint8_t*)"\3\2\1\1",4);
	pdu->setURI((char*)"newVersion", 10);
	pdu->setPayload((uint8_t*)payload,strlen(payload));

	// structure for getting address of incoming packets
    sockaddr_in fromAddr;
    socklen_t fromAddrLen = sizeof(struct sockaddr_in);
    memset(&fromAddr,0x00,fromAddrLen);
	int tryNum = 3;
	int ret = 0;
	// send packets to server
    do {
        // set PDU parameters
        pdu->setMessageID(++messageID);

		// send packet 
		ret = dtls_write(dtls_context, &g_dst, pdu->getPDUPointer(), pdu->getPDULength());
		if(ret!=pdu->getPDULength()) {
			INFO("Error sending packet.");
			pdu->reset();
			delete pdu;
			lostConnectionFlag = 1;
			NetLED_ticker.detach();
			NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
			return -2;
		}
//        INFO("Packet sent");

        // receive response
		do {
			char buffer[BUFLEN] = {0};
			session_t session;
			memset(&session, 0, sizeof(session_t));
			session.size = sizeof(session.addr);

			ret = recvfrom(sockfd, &buffer, BUFLEN, 0, &session.addr.sa, &session.size);
			if(ret==-1) {
				INFO("Error receiving data");
				pdu->reset();
				delete pdu;
				lostConnectionFlag = 1;
				NetLED_ticker.detach();
				NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
				return -3;
			}
//			INFO("session address family: %d, size: %d",session.addr.sa.sa_family,session.size);
//			INFO("Received %d bytes from %s:%d",ret,inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port));
			if(ret > BUFLEN) {
				INFO("PDU too large to fit in pre-allocated buffer");
				tryNum--;
				break;
			} else if(ret > 0) {
				buffer[ret] = 0x00;
				#if __DEBUG__ > 0
				unsigned char addrbuf[72];
				dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
				DBG("Got %d bytes from %s", len, (char *)addrbuf);
				dump((unsigned char *)&session, sizeof(session_t));
				DBGX("\r\n");
				dump(buf, len);
				DBGX("\r\n");
				#endif
			}
//			INFO("calling dtls_handle_message with context: %lx, session: %lx, buf: %lx, bytes: %d",
//				(unsigned long)dtls_context,(unsigned long)&session,(unsigned long)buffer, ret);
			dtls_handle_message(dtls_context, &session, (uint8_t*)buffer, ret);

			// reuse the below coap object
			CoapPDU *recvPDU = new CoapPDU(clearText, clearTextLen, clearTextLen);
			// validate packet
			recvPDU->setPDULength(clearTextLen);
			if(recvPDU->validate()!=1) {
				INFO("Malformed CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -4;
			}
#if 0
			INFO("Valid CoAP PDU received");
			recvPDU->printHuman();
#endif
			if (recvPDU->getMessageID() != messageID) {
				INFO("Unmatched CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				continue;
			}

			MbedJSONValue recvJson;
			parse(recvJson, (char *)recvPDU->getPayloadPointer());
			jsonStr = recvJson.serialize();
			printf("\r%s : [Packet receive] = %s\r\n" , __func__, jsonStr.c_str());
			if (recvJson.hasMember((char *)SUCCESS) && recvJson[SUCCESS].get<bool>()) {
				memset(&updateinfo, 0, sizeof(GetUpdateinfo));
				//Get the filename and newVersionNo
				if (recvJson.hasMember((char *)TYPE) && recvJson.hasMember((char *)NEWVERSIONNO)) {
					updateinfo.type = recvJson[TYPE].get<int>();
					if (strlen(recvJson[NEWVERSIONNO].get<string>().c_str()) <= HDR_NAME_8CHAR_LEN)
						strcpy(updateinfo.newVersionNo, recvJson[NEWVERSIONNO].get<string>().c_str());
//					printf("type = %s, newVersionNo = %s.........\n", updateinfo.type?"User":"Myself", updateinfo.newVersionNo);
					for (int i = 0; i < recvJson[FILENAMES].size(); i++) {
						if (strlen(recvJson[FILENAMES][i].get<string>().c_str()) <= FILENAME_MAX_LEN)
							strcpy(updateinfo.fileNames[i], recvJson[FILENAMES][i].get<string>().c_str());
//  					printf("\rThe %d filename is %s.........\n", i, updateinfo.fileNames[i]);
					}
					recvPDU->reset();
					delete recvPDU;
					pdu->reset();
					delete pdu;
					if (lostConnectionFlag == 1) {
						lostConnectionFlag = 0;
						NetLED_ticker.detach();
						NetLED_ticker.attach(&toggle_NetLed, 0.5);	//net is again connect
					}
					return 0;
				} else {
					recvPDU->reset();
					delete recvPDU;
					pdu->reset();
					delete pdu;
					return -5;
				}
			} else {
				tryNum--;
				recvPDU->reset();
				delete recvPDU;
				break;
			}
		} while (true);

        Thread::wait(3000);
    } while (tryNum);

	pdu->reset();
	delete pdu;
	return -1;
}

int deviceGetSaveUpdatefile(int sockfd) {
	DataLED_ticker.detach();
	DataLED_ticker.attach(&toggle_DataLed, 0.1);
	MbedJSONValue json;
	json["devUniqId"] = (string)deviceUniqId;
	json["type"] = updateinfo.type;
	json["fileName"] = updateinfo.fileNames[0];
	json["newVersionNo"] = updateinfo.newVersionNo;

	string jsonStr = json.serialize();
	printf("\r%s : [Packet sending] = %s\r\n" , __func__, jsonStr.c_str());

	char *payload = (char *)jsonStr.c_str();

	int ret = 0;
	int coapBlockNum = 0;
	int nextCoapBlock = 0;

	SPI spi(PC_3, PC_2, PB_13);   // mosi, miso, sclk
	spi.format(8, 0);
	spi.frequency(16 * 1000 * 1000);
	flash25spi w25q64(&spi, PB_12);

	UINT32 blockAddr = USER_IMG_MAP_BUF_CLEAR_FLAG;
	UINT32 brotherBlockAddr = USER_IMG_MAP_BUF_CLEAR_FLAG;

	for (int i = 0; i < 2; i++) {
		int bufFlagValue;
		if (w25q64.read(USER_IMG_MAP_BUF_START + i * USER_IMG_MAP_BUF_SIZE, 
				USER_IMG_MAP_BUF_FLAG_LEN, (char *)&bufFlagValue) == false) {
			INFO("Read user image bufFlagValue from flash failure");
			continue;
		}
//		printf("block%d, blockAddr[0x%08X], bufFlagValue[0x%08X].........\n", i,
//				USER_IMG_MAP_BUF_START + i * USER_IMG_MAP_BUF_SIZE, bufFlagValue);
		if (bufFlagValue == USER_IMG_MAP_BUF_CLEAR_FLAG) {
			int bufFlag = USER_IMG_MAP_BUF_VAILE_FLAG;
			w25q64.write(USER_IMG_MAP_BUF_START + i * USER_IMG_MAP_BUF_SIZE, USER_IMG_MAP_BUF_FLAG_LEN, (char *)&bufFlag);
			if (i == 0) {
				blockAddr = USER_IMG_MAP_BUF_START + USER_IMG_MAP_BUF_FLAG_LEN;
				brotherBlockAddr = USER_IMG_MAP_BUF_START + USER_IMG_MAP_BUF_SIZE;
			} else if (i == 1) {
				blockAddr = USER_IMG_MAP_BUF_START + USER_IMG_MAP_BUF_SIZE + USER_IMG_MAP_BUF_FLAG_LEN;
				brotherBlockAddr = USER_IMG_MAP_BUF_START;
			}
			for (int i = 0; i < USER_IMG_MAP_BUF_SIZE/USER_IMG_MAP_BLOCK_SIZE; i++)
				w25q64.clearBlock(brotherBlockAddr + i*USER_IMG_MAP_BLOCK_SIZE);
			break;
		}
	}
	if (blockAddr == USER_IMG_MAP_BUF_CLEAR_FLAG || brotherBlockAddr == USER_IMG_MAP_BUF_CLEAR_FLAG) {
		INFO("No valid flash is available");
		return  -1;
	}

	int tryNum = 5;
	do {
		if (coapBlockNum%56 == 0) {
			// start the device status report
			int tryNum1 = 3;
			do {
				ret = deviceStatusReport(sockfd, 2);
				if (ret)
					Thread::wait(100);
			} while(ret && tryNum1--);
			if (ret) {
				INFO("Error sending updateing statusReport packet.");
				return -2;
			}
		}

		// construct CoAP packetsss
		CoapPDU *pdu = new CoapPDU();
		pdu->setVersion(1);
		pdu->setType(CoapPDU::COAP_CONFIRMABLE);
		pdu->setCode(CoapPDU::COAP_POST);
		pdu->setToken((uint8_t*)"\3\2\1\1",4);
		pdu->setURI((char*)"downfile", 8);
		unsigned short coapBlockValue = (coapBlockNum<<4) | 0x6;
		coapBlockValue = ((coapBlockValue&0xFF)<<8) | ((coapBlockValue>>8)&0xFF);
		pdu->addOption(CoapPDU::COAP_OPTION_BLOCK2, 2, (uint8_t *)&coapBlockValue);
		pdu->setPayload((uint8_t*)payload,strlen(payload));
		// set PDU parameters
		pdu->setMessageID(++messageID);

		// send packet 
		ret = dtls_write(dtls_context, &g_dst, pdu->getPDUPointer(), pdu->getPDULength());
		if(ret!=pdu->getPDULength()) {
			INFO("Error sending packet.");
			pdu->reset();
			delete pdu;
			nextCoapBlock = 1;
			continue;
		}
//        INFO("Packet sent");


		// receive response
		do {
			char recvBuffer[RECVBUFLEN] = {0};
			session_t session;
			memset(&session, 0, sizeof(session_t));
			session.size = sizeof(session.addr);

			ret = recvfrom(sockfd, &recvBuffer, RECVBUFLEN, 0, &session.addr.sa, &session.size);
			if(ret==-1) {
				INFO("Error receiving data");
				pdu->reset();
				delete pdu;
				if (tryNum--) {
//					Thread::wait(1000);
					nextCoapBlock = 1;
					break;
				} else {
					INFO("Failed to recvfrom bytes attempts to eight times");
					return -3;
				}
			} else if(ret > RECVBUFLEN) {
				INFO("PDU too large to fit in pre-allocated buffer");
				tryNum--;
				break;
			} else if(ret > 0) {
				recvBuffer[ret] = 0x00;
				#if __DEBUG__ > 0
				unsigned char addrbuf[72];
				dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
				DBG("Got %d bytes from %s", len, (char *)addrbuf);
				dump((unsigned char *)&session, sizeof(session_t));
				DBGX("\r\n");
				dump(buf, len);
				DBGX("\r\n");
				#endif
			}
//			INFO("calling dtls_handle_message with context: %lx, session: %lx, buf: %lx, bytes: %d",
//				(unsigned long)dtls_context,(unsigned long)&session,(unsigned long)recvBuffer, ret);
			dtls_handle_message(dtls_context, &session, (uint8_t*)recvBuffer, ret);

			tryNum = 5;
//			INFO("session address family: %d, size: %d",session.addr.sa.sa_family,session.size);
//			INFO("Received %d bytes from %s:%d",ret,inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port));

			// reuse the below coap object
			CoapPDU *recvPDU = new CoapPDU(clearText, clearTextLen, clearTextLen);
			// validate packet
			recvPDU->setPDULength(clearTextLen);
			if(recvPDU->validate()!=1) {
				INFO("Malformed CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -4;
			}
#if 0
			INFO("Valid CoAP PDU received");
			recvPDU->printHuman();
#endif
			if (recvPDU->getMessageID() != messageID) {
				INFO("Unmatched CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				continue;
			}

			if (recvPDU->getContentFormat() == CoapPDU::COAP_CONTENT_FORMAT_TEXT_PLAIN) {
				MbedJSONValue recvJson;
				parse(recvJson, (char *)recvPDU->getPayloadPointer());
				jsonStr = recvJson.serialize();
				printf("\r%s : [Packet receive] = %s\r\n" , __func__, jsonStr.c_str());
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -5;
			}

			char *payload = (char *)recvPDU->getPayloadPointer();
			int payloadLen = recvPDU->getPayloadLength();
			updateinfo.fileLength += payloadLen;

			if (w25q64.write(blockAddr + coapBlockNum * BAG_1K_SIZE, payloadLen, payload) == false) {
				INFO("Error write the flash");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -5;
			}

			nextCoapBlock = recvPDU->getOptionsBlock2Next();
			recvPDU->reset();
			delete recvPDU;
			pdu->reset();
			delete pdu;
			coapBlockNum++;
			break;
		} while (true);
	} while (nextCoapBlock);

	return 0;
}


int deviceGetSelfVerinfo(int sockfd) {
	char str[64] = {0};
	MbedJSONValue json;
	strncpy(str, header.devType, HDR_NAME_8CHAR_LEN);
	json["devType"] = str;

	memset(str, 0, sizeof(str));
	strncpy(str, header.hardVerNo, HDR_NAME_8CHAR_LEN);
	json["hardVerNo"] = str;

	string jsonStr = json.serialize();
	printf("\r%s : [Packet sending] = %s\r\n" , __func__, jsonStr.c_str());

	char *payload = (char *)jsonStr.c_str();
    // construct CoAP packet
    CoapPDU *pdu = new CoapPDU();
    pdu->setVersion(1);
    pdu->setType(CoapPDU::COAP_CONFIRMABLE);
    pdu->setCode(CoapPDU::COAP_POST);
    pdu->setToken((uint8_t*)"\3\2\1\1",4);
	pdu->setURI((char*)"lastestVersion", 14);
	pdu->setPayload((uint8_t*)payload,strlen(payload));

	// structure for getting address of incoming packets
    sockaddr_in fromAddr;
    socklen_t fromAddrLen = sizeof(struct sockaddr_in);
    memset(&fromAddr,0x00,fromAddrLen);
	int tryNum = 3;
	int ret = 0;
	// send packets to server
    do {
        // set PDU parameters
        pdu->setMessageID(++messageID);

		// send packet 
		ret = dtls_write(dtls_context, &g_dst, pdu->getPDUPointer(), pdu->getPDULength());
		if(ret!=pdu->getPDULength()) {
			INFO("Error sending packet.");
			pdu->reset();
			delete pdu;
			lostConnectionFlag = 1;
			NetLED_ticker.detach();
			NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
			return -2;
		}
//        INFO("Packet sent");

        // receive response
		do {
			char buffer[BUFLEN] = {0};
			session_t session;
			memset(&session, 0, sizeof(session_t));
			session.size = sizeof(session.addr);

			ret = recvfrom(sockfd, &buffer, BUFLEN, 0, &session.addr.sa, &session.size);
			if(ret==-1) {
				INFO("Error receiving data");
				pdu->reset();
				delete pdu;
				lostConnectionFlag = 1;
				NetLED_ticker.detach();
				NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
				return -3;
			}
//			INFO("session address family: %d, size: %d",session.addr.sa.sa_family,session.size);
//			INFO("Received %d bytes from %s:%d",ret,inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port));
			if(ret > BUFLEN) {
				INFO("PDU too large to fit in pre-allocated buffer");
				tryNum--;
				break;
			} else if(ret > 0) {
				buffer[ret] = 0x00;
				#if __DEBUG__ > 0
				unsigned char addrbuf[72];
				dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
				DBG("Got %d bytes from %s", len, (char *)addrbuf);
				dump((unsigned char *)&session, sizeof(session_t));
				DBGX("\r\n");
				dump(buf, len);
				DBGX("\r\n");
				#endif
			}
//			INFO("calling dtls_handle_message with context: %lx, session: %lx, buf: %lx, bytes: %d",
//				(unsigned long)dtls_context,(unsigned long)&session,(unsigned long)buffer, ret);
			dtls_handle_message(dtls_context, &session, (uint8_t*)buffer, ret);

			// reuse the below coap object
			CoapPDU *recvPDU = new CoapPDU(clearText, clearTextLen, clearTextLen);
			// validate packet
			recvPDU->setPDULength(clearTextLen);
			if(recvPDU->validate()!=1) {
				INFO("Malformed CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -4;
			}
#if 0
			INFO("Valid CoAP PDU received");
			recvPDU->printHuman();
#endif
			if (recvPDU->getMessageID() != messageID) {
				INFO("Unmatched CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				continue;
			}

			MbedJSONValue recvJson;
			parse(recvJson, (char *)recvPDU->getPayloadPointer());
			jsonStr = recvJson.serialize();
			printf("\r%s : [Packet receive] = %s\r\n" , __func__, jsonStr.c_str());
			if (recvJson.hasMember((char *)SUCCESS) && recvJson[SUCCESS].get<bool>()) {
				memset(&selfUpdateinfo, 0, sizeof(GetSelfUpdateinfo));
				//Get the filename and newVersionNo
				if (recvJson.hasMember((char *)NEWVERSIONNO)) {
					if (strlen(recvJson[NEWVERSIONNO].get<string>().c_str()) <= HDR_NAME_8CHAR_LEN)
						strcpy(selfUpdateinfo.newVersionNo, recvJson[NEWVERSIONNO].get<string>().c_str());

					recvPDU->reset();
					delete recvPDU;
					pdu->reset();
					delete pdu;
					if (lostConnectionFlag == 1) {
						lostConnectionFlag = 0;
						NetLED_ticker.detach();
						NetLED_ticker.attach(&toggle_NetLed, 0.5);	//net is again connect
					}
					return 0;
				} else {
					recvPDU->reset();
					delete recvPDU;
					pdu->reset();
					delete pdu;
					return -5;
				}
			} else {
				tryNum--;
				recvPDU->reset();
				delete recvPDU;
				break;
			}
		} while (true);

        Thread::wait(3000);
    } while (tryNum);

	pdu->reset();
	delete pdu;
	return -1;
}

int deviceGetSaveSelfUpdatefile(int sockfd) {
	CfgLED_ticker.detach();
	CfgLED_ticker.attach(&toggle_CfgLed, 0.1);
	char str[64] = {0};
	MbedJSONValue json;
	json["newVersionNo"] = selfUpdateinfo.newVersionNo;

	strncpy(str, header.devType, HDR_NAME_8CHAR_LEN);
	json["devType"] = str;

	memset(str, 0, sizeof(str));
	strncpy(str, header.hardVerNo, HDR_NAME_8CHAR_LEN);
	json["hardVerNo"] = str;

	string jsonStr = json.serialize();
	printf("\r%s : [Packet sending] = %s\r\n" , __func__, jsonStr.c_str());

	char *payload = (char *)jsonStr.c_str();

	int ret = 0;
	int coapBlockNum = 0;
	int nextCoapBlock = 0;

	SPI spi(PC_3, PC_2, PB_13);   // mosi, miso, sclk
	spi.format(8, 0);
	spi.frequency(16 * 1000 * 1000);
	flash25spi w25q64(&spi, PB_12);

	//Stored in the partition 2 for the first time
	UINT32 blockAddr = SELF_IMG_MAP_BUF2_START;
	selfUpdateinfo.addrNum = 2;

	if (header.selfUpdateFileInfo[1] == 1) {
		blockAddr = SELF_IMG_MAP_BUF2_START;
		selfUpdateinfo.addrNum = 2;
	} else if (header.selfUpdateFileInfo[1] == 2) {
		blockAddr = SELF_IMG_MAP_BUF1_START;
		selfUpdateinfo.addrNum = 1;
	}

	for (int i = 0; i < SELF_IMG_MAP_BUF_SIZE/SELF_IMG_MAP_BLOCK_SIZE; i++) {
		w25q64.clearBlock(blockAddr + i*SELF_IMG_MAP_BLOCK_SIZE);
	}

	int tryNum = 8;
	do {
		// construct CoAP packetsss
		CoapPDU *pdu = new CoapPDU();
		pdu->setVersion(1);
		pdu->setType(CoapPDU::COAP_CONFIRMABLE);
		pdu->setCode(CoapPDU::COAP_POST);
		pdu->setToken((uint8_t*)"\3\2\1\1",4);
		pdu->setURI((char*)"lastestFile", 11);
		unsigned short coapBlockValue = (coapBlockNum<<4) | 0x6;
		coapBlockValue = ((coapBlockValue&0xFF)<<8) | ((coapBlockValue>>8)&0xFF);
		pdu->addOption(CoapPDU::COAP_OPTION_BLOCK2, 2, (uint8_t *)&coapBlockValue);
		pdu->setPayload((uint8_t*)payload,strlen(payload));
		// set PDU parameters
		pdu->setMessageID(++messageID);

		// send packet 
		ret = dtls_write(dtls_context, &g_dst, pdu->getPDUPointer(), pdu->getPDULength());
		if(ret!=pdu->getPDULength()) {
			INFO("Error sending packet.");
			pdu->reset();
			delete pdu;
			nextCoapBlock = 1;
			continue;
		}
//        INFO("Packet sent");

		// receive response
		do {
			char recvBuffer[RECVBUFLEN] = {0};
			session_t session;
			memset(&session, 0, sizeof(session_t));
			session.size = sizeof(session.addr);

			ret = recvfrom(sockfd, &recvBuffer, RECVBUFLEN, 0, &session.addr.sa, &session.size);
			if(ret==-1) {
				INFO("Error receiving data");
				pdu->reset();
				delete pdu;
				if (tryNum--) {
//					Thread::wait(1000);
					nextCoapBlock = 1;
					break;
				} else {
					INFO("Failed to recvfrom bytes attempts to eight times");
					return -3;
				}
			} else if(ret > RECVBUFLEN) {
				INFO("PDU too large to fit in pre-allocated buffer");
				tryNum--;
				break;
			} else if(ret > 0) {
				recvBuffer[ret] = 0x00;
				#if __DEBUG__ > 0
				unsigned char addrbuf[72];
				dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
				DBG("Got %d bytes from %s", len, (char *)addrbuf);
				dump((unsigned char *)&session, sizeof(session_t));
				DBGX("\r\n");
				dump(buf, len);
				DBGX("\r\n");
				#endif
			}
//			INFO("calling dtls_handle_message with context: %lx, session: %lx, buf: %lx, bytes: %d",
//				(unsigned long)dtls_context,(unsigned long)&session,(unsigned long)recvBuffer, ret);
			dtls_handle_message(dtls_context, &session, (uint8_t*)recvBuffer, ret);

			tryNum = 8;
//			INFO("session address family: %d, size: %d",session.addr.sa.sa_family,session.size);
//			INFO("Received %d bytes from %s:%d",ret,inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port));

			// reuse the below coap object
			CoapPDU *recvPDU = new CoapPDU(clearText, clearTextLen, clearTextLen);
			// validate packet
			recvPDU->setPDULength(clearTextLen);
			if(recvPDU->validate()!=1) {
				INFO("Malformed CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -4;
			}
#if 0
			INFO("Valid CoAP PDU received");
			recvPDU->printHuman();
#endif
			if (recvPDU->getMessageID() != messageID) {
				INFO("Unmatched CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				continue;
			}

			if (recvPDU->getContentFormat() == CoapPDU::COAP_CONTENT_FORMAT_TEXT_PLAIN) {
				MbedJSONValue recvJson;
				parse(recvJson, (char *)recvPDU->getPayloadPointer());
				jsonStr = recvJson.serialize();
				printf("\r%s : [Packet receive] = %s\r\n" , __func__, jsonStr.c_str());
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -5;
			}

			char *payload = (char *)recvPDU->getPayloadPointer();
			int payloadLen = recvPDU->getPayloadLength();
			selfUpdateinfo.fileLength += payloadLen;

			if (w25q64.write(blockAddr + coapBlockNum * BAG_1K_SIZE, payloadLen, payload) == false) {
				INFO("Error write the flash");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -5;
			}

			nextCoapBlock = recvPDU->getOptionsBlock2Next();
			recvPDU->reset();
			delete recvPDU;
			pdu->reset();
			delete pdu;
			coapBlockNum++;
			break;
		} while (true);
	} while (nextCoapBlock);

	if (setSelfUpdateFileInfo(1) == false)
		return -6;

	return 0;
}

int deviceResponseStringResultCommand(int sockfd, ServerRequestCommand cmd, char *res) {
	MbedJSONValue json;
	char str[1024] = {0};
	UINT logType = 0;
	switch(cmd) {
		case SERVER_REQUEST_RANDOM_COMMAND: {
			userfwpro userFWPro(&userCom);
			userFWPro.init();
			if (userFWPro.getUserDevRegNum(deviceRandomNum, sizeof(deviceRandomNum)) == 0 &&
				strlen(deviceRandomNum) != 0) {
				json["result"] = deviceRandomNum;
			} else {
				strcpy(deviceRandomNum, "__NULL");
				json["result"] = "__NULL";
			}
			break;
		}
		case SERVER_REQUEST_EVAL_COMMAND:
			json["result"] = res;
			break;
		default:
			json["result"] = "__NULL";
			break;
	}

	json["devUniqId"] = (string)deviceUniqId;
	json["command"]	= serverRequestCommand;

	string jsonStr = json.serialize();
	printf("\r%s : [Packet sending] = %s\r\n" , __func__, jsonStr.c_str());

	char *payload = (char *)jsonStr.c_str();
    // construct CoAP packet
    CoapPDU *pdu = new CoapPDU();
    pdu->setVersion(1);
    pdu->setType(CoapPDU::COAP_CONFIRMABLE);
    pdu->setCode(CoapPDU::COAP_POST);
    pdu->setToken((uint8_t*)"\3\2\1\1",4);
	pdu->setURI((char*)"devQA/recvDevInfo", 17);
	pdu->setPayload((uint8_t*)payload,strlen(payload));

	// structure for getting address of incoming packets
    sockaddr_in fromAddr;
    socklen_t fromAddrLen = sizeof(struct sockaddr_in);
    memset(&fromAddr,0x00,fromAddrLen);
	int tryNum = 5;
	int ret = 0;
	// send packets to server
    do {
        // set PDU parameters
        pdu->setMessageID(++messageID);

		// send packet 
		ret = dtls_write(dtls_context, &g_dst, pdu->getPDUPointer(), pdu->getPDULength());
		if(ret!=pdu->getPDULength()) {
			INFO("Error sending packet.");
			pdu->reset();
			delete pdu;
			lostConnectionFlag = 1;
			NetLED_ticker.detach();
			NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
			return -2;
		}

        // receive response
		do {
			char buffer[BUFLEN] = {0};
			session_t session;
			memset(&session, 0, sizeof(session_t));
			session.size = sizeof(session.addr);

			ret = recvfrom(sockfd, &buffer, BUFLEN, 0, &session.addr.sa, &session.size);
			if(ret==-1) {
				INFO("Error receiving data");
				pdu->reset();
				delete pdu;
				lostConnectionFlag = 1;
				NetLED_ticker.detach();
				NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
				return -3;
			}
			if(ret > BUFLEN) {
				INFO("PDU too large to fit in pre-allocated buffer");
				tryNum--;
				break;
			} else if(ret > 0) {
				buffer[ret] = 0x00;
				#if __DEBUG__ > 0
				unsigned char addrbuf[72];
				dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
				DBG("Got %d bytes from %s", len, (char *)addrbuf);
				dump((unsigned char *)&session, sizeof(session_t));
				DBGX("\r\n");
				dump(buf, len);
				DBGX("\r\n");
				#endif
			}
			dtls_handle_message(dtls_context, &session, (uint8_t*)buffer, ret);

			// reuse the below coap object
			CoapPDU *recvPDU = new CoapPDU(clearText, clearTextLen, clearTextLen);
			// validate packet
			recvPDU->setPDULength(clearTextLen);
			if(recvPDU->validate()!=1) {
				INFO("Malformed CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -4;
			}
			if (recvPDU->getMessageID() != messageID) {
				INFO("Unmatched CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				continue;
			}

			MbedJSONValue recvJson;
			parse(recvJson, (char *)recvPDU->getPayloadPointer());
			jsonStr = recvJson.serialize();
			printf("\r%s : [Packet receive] = %s\r\n" , __func__, jsonStr.c_str());
			if (recvJson.hasMember((char *)SUCCESS) && recvJson[SUCCESS].get<bool>()) {
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				if (lostConnectionFlag == 1) {
					lostConnectionFlag = 0;
					NetLED_ticker.detach();
					NetLED_ticker.attach(&toggle_NetLed, 0.5);	//net is again connect
				}
				return 0;
			} else {
				tryNum--;
			recvPDU->reset();
				delete recvPDU;
				break;
			}
		} while (true);

        Thread::wait(3000);
    } while (tryNum);

	pdu->reset();
	delete pdu;
	return -1;
}

int deviceResponseBinaryResultCommand(int sockfd, ServerRequestCommand cmd) {
	char str[1024] = {0};
	UINT16 datLen = 0;
	memcpy(&str[0], deviceUniqId, sizeof(header.devId));
	memcpy(&str[sizeof(header.devId)], serverRequestCommand, 10);
	userfwpro userFWPro(&userCom);
	userFWPro.init();
	switch(cmd) {
		case SERVER_REQUEST_ITEMA_COMMAND:
		case SERVER_REQUEST_ITEMB_COMMAND:
		case SERVER_REQUEST_ITEMC_COMMAND:
		case SERVER_REQUEST_ITEMD_COMMAND:
		case SERVER_REQUEST_ITEME_COMMAND:
		case SERVER_REQUEST_ITEMF_COMMAND: {
			UINT logType = 0;
			switch(cmd) {
				case SERVER_REQUEST_ITEMA_COMMAND: logType = 1; break;
				case SERVER_REQUEST_ITEMB_COMMAND: logType = 2; break;
				case SERVER_REQUEST_ITEMC_COMMAND: logType = 3; break;
				case SERVER_REQUEST_ITEMD_COMMAND: logType = 4; break;
				case SERVER_REQUEST_ITEME_COMMAND: logType = 5; break;
				case SERVER_REQUEST_ITEMF_COMMAND: logType = 6; break;
				default: logType = 0; break;
			}
			if (userFWPro.getUserDevLogRecord(logType, &str[sizeof(header.devId)+10], sizeof(str)-sizeof(header.devId)-10) == 0) {
				datLen = (str[sizeof(header.devId)+10]*0x100+str[sizeof(header.devId)+11])*sizeof(struct sysLogRecord);
			} else {
				//????????????????????
				datLen = 0;
				str[sizeof(header.devId)+10] = 0;
				str[sizeof(header.devId)+11] = 0;
			}
			break;
		}
		case SERVER_REQUEST_CONFIGS_COMMAND: {
			userfwpro userFWPro(&userCom);
			userFWPro.init();
			if (userFWPro.getUserDevCfgParam(&str[sizeof(header.devId)+10], sizeof(str)-sizeof(header.devId)-10) == 0){
				datLen = str[sizeof(header.devId)+10]*0x100+str[sizeof(header.devId)+11];
			} else {
				//????????????????????
				datLen = 0;
				str[sizeof(header.devId)+10] = 0;
				str[sizeof(header.devId)+11] = 0;
			}
			break;
		}
		case SERVER_REQUEST_SCANPORTS_COMMAND: {
			if (userFWPro.getUserDevStaData(&str[sizeof(header.devId)+12], sizeof(str)-sizeof(header.devId)-12) == 0){
				str[sizeof(header.devId)+10] = 0x00;
				str[sizeof(header.devId)+11] = 0x0A;
				datLen = str[sizeof(header.devId)+10]*0x100+str[sizeof(header.devId)+11];
			} else {
				str[sizeof(header.devId)+10] = 0;
				str[sizeof(header.devId)+11] = 0;
				datLen = 0;
			}
			break;
		}
		default:
			datLen = 0;
			str[sizeof(header.devId)+10] = 0;
			str[sizeof(header.devId)+11] = 0;
			break;
	}

	printf("\r%s : [Packet sending]\r\n" , __func__);

	char *payload = str;
    // construct CoAP packet
    CoapPDU *pdu = new CoapPDU();
    pdu->setVersion(1);
    pdu->setType(CoapPDU::COAP_CONFIRMABLE);
    pdu->setCode(CoapPDU::COAP_POST);
    pdu->setToken((uint8_t*)"\3\2\1\1",4);
	pdu->setURI((char*)"devQA/recvDevBytes", 18);
	pdu->setPayload((uint8_t*)payload, sizeof(header.devId)+10+2+datLen);
	pdu->addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT, 1, (uint8_t*)CoapPDU::COAP_CONTENT_FORMAT_APP_OCTET);

	// structure for getting address of incoming packets
    sockaddr_in fromAddr;
    socklen_t fromAddrLen = sizeof(struct sockaddr_in);
    memset(&fromAddr,0x00,fromAddrLen);
	int tryNum = 3;
	int ret = 0;
	// send packets to server
    do {
        // set PDU parameters
        pdu->setMessageID(++messageID);

		// send packet 
		ret = dtls_write(dtls_context, &g_dst, pdu->getPDUPointer(), pdu->getPDULength());
		if(ret!=pdu->getPDULength()) {
			INFO("Error sending packet.");
			pdu->reset();
			delete pdu;
			lostConnectionFlag = 1;
			NetLED_ticker.detach();
			NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
			return -2;
		}

        // receive response
		do {
			char buffer[BUFLEN] = {0};
			session_t session;
			memset(&session, 0, sizeof(session_t));
			session.size = sizeof(session.addr);

			ret = recvfrom(sockfd, &buffer, BUFLEN, 0, &session.addr.sa, &session.size);
			if(ret==-1) {
				INFO("Error receiving data");
				pdu->reset();
				delete pdu;
				lostConnectionFlag = 1;
				NetLED_ticker.detach();
				NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
				return -3;
			}
			if(ret > BUFLEN) {
				INFO("PDU too large to fit in pre-allocated buffer");
				tryNum--;
				break;
			} else if(ret > 0) {
				buffer[ret] = 0x00;
				#if __DEBUG__ > 0
				unsigned char addrbuf[72];
				dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
				DBG("Got %d bytes from %s", len, (char *)addrbuf);
				dump((unsigned char *)&session, sizeof(session_t));
				DBGX("\r\n");
				dump(buf, len);
				DBGX("\r\n");
				#endif
			}
			dtls_handle_message(dtls_context, &session, (uint8_t*)buffer, ret);

			// reuse the below coap object
			CoapPDU *recvPDU = new CoapPDU(clearText, clearTextLen, clearTextLen);
			// validate packet
			recvPDU->setPDULength(clearTextLen);
			if(recvPDU->validate()!=1) {
				INFO("Malformed CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -4;
			}
			if (recvPDU->getMessageID() != messageID) {
				INFO("Unmatched CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				continue;
			}

			MbedJSONValue recvJson;
			parse(recvJson, (char *)recvPDU->getPayloadPointer());
			string jsonStr = recvJson.serialize();
			printf("\r%s : [Packet receive] = %s\r\n" , __func__, jsonStr.c_str());
			if (recvJson.hasMember((char *)SUCCESS) && recvJson[SUCCESS].get<bool>()) {
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				if (lostConnectionFlag == 1) {
					lostConnectionFlag = 0;
					NetLED_ticker.detach();
					NetLED_ticker.attach(&toggle_NetLed, 0.5);	//net is again connect
				}
				return 0;
			} else {
				tryNum--;
				recvPDU->reset();
				delete recvPDU;
				break;
			}
		} while (true);

        Thread::wait(3000);
    } while (tryNum);

	pdu->reset();
	delete pdu;
	return -1;
}

int deviceResponseEvalCommand(int sockfd) {
	MbedJSONValue json;
	json["devUniqId"] = (string)deviceUniqId;
	json["command"]	= serverRequestCommand;
	json["random"] = deviceRandomNum;

	string jsonStr = json.serialize();
	printf("\r%s : [Packet sending] = %s\r\n" , __func__, jsonStr.c_str());

	char *payload = (char *)jsonStr.c_str();
    // construct CoAP packet
    CoapPDU *pdu = new CoapPDU();
    pdu->setVersion(1);
    pdu->setType(CoapPDU::COAP_CONFIRMABLE);
    pdu->setCode(CoapPDU::COAP_POST);
    pdu->setToken((uint8_t*)"\3\2\1\1",4);
	pdu->setURI((char*)"devQA/keyAccess", 15);
	pdu->setPayload((uint8_t*)payload,strlen(payload));

	// structure for getting address of incoming packets
    sockaddr_in fromAddr;
    socklen_t fromAddrLen = sizeof(struct sockaddr_in);
    memset(&fromAddr,0x00,fromAddrLen);
	int tryNum = 5;
	int ret = 0;
	// send packets to server
    do {
        // set PDU parameters
        pdu->setMessageID(++messageID);

		// send packet 
		ret = dtls_write(dtls_context, &g_dst, pdu->getPDUPointer(), pdu->getPDULength());
		if(ret!=pdu->getPDULength()) {
			INFO("Error sending packet.");
			pdu->reset();
			delete pdu;
			lostConnectionFlag = 1;
			NetLED_ticker.detach();
			NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
			return -2;
		}

        // receive response
		do {
			char buffer[BUFLEN] = {0};
			session_t session;
			memset(&session, 0, sizeof(session_t));
			session.size = sizeof(session.addr);

			ret = recvfrom(sockfd, &buffer, BUFLEN, 0, &session.addr.sa, &session.size);
			if(ret==-1) {
				INFO("Error receiving data");
				pdu->reset();
				delete pdu;
				lostConnectionFlag = 1;
				NetLED_ticker.detach();
				NetLED_ticker.attach(&toggle_NetLed, 3);	//net is connect
				return -3;
			}
			if(ret > BUFLEN) {
				INFO("PDU too large to fit in pre-allocated buffer");
				tryNum--;
				break;
			} else if(ret > 0) {
				buffer[ret] = 0x00;
				#if __DEBUG__ > 0
				unsigned char addrbuf[72];
				dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
				DBG("Got %d bytes from %s", len, (char *)addrbuf);
				dump((unsigned char *)&session, sizeof(session_t));
				DBGX("\r\n");
				dump(buf, len);
				DBGX("\r\n");
				#endif
			}
			dtls_handle_message(dtls_context, &session, (uint8_t*)buffer, ret);

			// reuse the below coap object
			CoapPDU *recvPDU = new CoapPDU(clearText, clearTextLen, clearTextLen);
			// validate packet
			recvPDU->setPDULength(clearTextLen);
			if(recvPDU->validate()!=1) {
				INFO("Malformed CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				pdu->reset();
				delete pdu;
				return -4;
			}
			if (recvPDU->getMessageID() != messageID) {
				INFO("Unmatched CoAP packet");
				recvPDU->reset();
				delete recvPDU;
				continue;
			}

			MbedJSONValue recvJson;
			parse(recvJson, (char *)recvPDU->getPayloadPointer());
			jsonStr = recvJson.serialize();
			printf("\r%s : [Packet receive] = %s\r\n" , __func__, jsonStr.c_str());
			if (recvJson.hasMember((char *)SUCCESS) && recvJson[SUCCESS].get<bool>()) {
				if (recvJson.hasMember((char *)"data")) {
					char str[32] = {0};
					if (strlen(recvJson["data"].get<string>().c_str()) <= sizeof(str)) {
						strcpy(str, recvJson["data"].get<string>().c_str());
						char *p = strstr(str, "::");
						if (p) {
							*p = 0;
							UINT16 num = atoi(str);
							userfwpro userFWPro(&userCom);
							userFWPro.init();
							if (userFWPro.registerUserDevice(num, p+2) == 0)
								deviceResponseStringResultCommand(sockfd, SERVER_REQUEST_EVAL_COMMAND, (char *)"true");
							else
								deviceResponseStringResultCommand(sockfd, SERVER_REQUEST_EVAL_COMMAND, (char *)"false");
						} else {
							printf("Receive user device register code format is not reasonable!\r\n");
						}
					} else {
						printf("Receive user device register code error!\r\n");
					}
					recvPDU->reset();
					delete recvPDU;
					pdu->reset();
					delete pdu;
					if (lostConnectionFlag == 1) {
						lostConnectionFlag = 0;
						NetLED_ticker.detach();
						NetLED_ticker.attach(&toggle_NetLed, 0.5);	//net is again connect
					}
					return 0;
				} else {
					tryNum--;
					recvPDU->reset();
					delete recvPDU;
					break;
				}
			} else {
				tryNum--;
				recvPDU->reset();
				delete recvPDU;
				break;
			}
		} while (true);

        Thread::wait(3000);
    } while (tryNum);

	pdu->reset();
	delete pdu;
	return -1;
}

bool connectToSocketUDP(char *ipAddress, int port, int *sockfd) {
	sockaddr_in bindAddr,serverAddress;

	*sockfd = -1;
	// create the socket
	if((*sockfd=socket(AF_INET,SOCK_DGRAM,0))<0) {
		DBG("Error opening socket");
		return false;
	}
	socklen_t sockAddrInLen = sizeof(struct sockaddr_in);

	// bind socket to 11111
	memset(&bindAddr,  0x00, sockAddrInLen);
	bindAddr.sin_family = AF_INET; // IP family
	bindAddr.sin_port = htons(port);
	bindAddr.sin_addr.s_addr = IPADDR_ANY; // 32 bit IP representation
	// call bind
	if(bind(*sockfd,(const struct sockaddr *)&bindAddr,sockAddrInLen)!=0) {
		DBG("Error binding socket");
	}

	INFO("UDP socket created and bound to: %s:%d",inet_ntoa(bindAddr.sin_addr),ntohs(bindAddr.sin_port));

	// create the socket address
	memset(&serverAddress, 0x00, sizeof(struct sockaddr_in));
	serverAddress.sin_addr.s_addr = inet_addr(ipAddress);
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_port = htons(port);

	// do socket connect
	//LOG("Connecting socket to %s:%d", inet_ntoa(serverAddress.sin_addr), ntohs(serverAddress.sin_port));
	if(connect(*sockfd, (const struct sockaddr *)&serverAddress, sizeof(serverAddress))<0) {
		shutdown(*sockfd,SHUT_RDWR);
		close(*sockfd);
		DBG("Could not connect");
		return false;
	}

	int on = 1;
	if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
		DBG("Setsockopt SO_REUSEADDR: %s\n", strerror(errno));
	}

	// destination address is stored in a session type
	memset(&g_dst, 0, sizeof(session_t));
	g_dst.size = sizeof(sockaddr_in);
	serverAddress.sin_len  = g_dst.size;
	memcpy(&g_dst.addr.sa, &serverAddress, g_dst.size);

  return true;
}

void startRemoteUpdate(enum DeviceUpdateStep step) {
#if 0
	unsigned int mcuID[3] = {0};

	mcuID[0] = *(__IO u32*)(0x1FFF7A10);
	mcuID[1] = *(__IO u32*)(0x1FFF7A14);
	mcuID[2] = *(__IO u32*)(0x1FFF7A18);
	sprintf(deviceUniqId, "%08X%08X%08X", mcuID[2], mcuID[1]+1, mcuID[0]);
	INFO("The MCU uniqe ID is %s.", deviceUniqId);

	if (read_eeprom(&header) < 0)
		INFO("Could not get device ID\r\n");
#endif

    // setup socket to remote server
    int sockfd = NULL;
    if(!connectToSocketUDP(header.serverIp, atoi(header.serverPort), &sockfd)) {
       DBG("Error connecting to socket");
       return;
    }
    DBG("\"Connected\" to UDP socket");

	if (tinydtls_init(&sockfd)) {
		DBG("Error initialize the tinydtls to socket, will restart the device...");
		SoftReset();
	}

	strncpy(deviceUniqId, header.devId, HDR_NAME_12CHAR_LEN*2);

	int ret = 0, retryNum = 1;
	if (step == DEVICE_UPDATE_IDELING) {	//Only the device is idleing, detect the self app version
		do {
			ret = deviceGetSelfVerinfo(sockfd);
		} while(ret && --retryNum);
		if (ret == 0) {
			if (strcmp(selfUpdateinfo.newVersionNo, header.softVerNo)) {
				ret = deviceGetSaveSelfUpdatefile(sockfd);
				if (ret == 0) {
					printf("Download self device updatefile over, will restart the device......\n");
					SoftReset();
				} else {
					printf("Download self device updatefile failure, whether updatefile changes.??????\n");
				}
			}
		}
	}

	// register the device until register success or timeout 180s
	retryNum = 60;
	do {
		if (userFirmwareSendCompleteFlag == 1)
			step = DEVICE_UPDATE_IDELING;
		if (step == DEVICE_UPDATE_COMMAND || step == USER_DEVICE_UPDATE_COMPLETE)
			ret = deviceRegister(sockfd, 3);
		else
			ret = deviceRegister(sockfd, 1);
		if (ret)
			Thread::wait(3000);
	} while(ret && retryNum--);
	if (ret) {
		ERR("Device register failure, will restart the device......");
		NetLED_ticker.detach();
		NetLED_ticker.attach(&toggle_NetLed, 0);	//register is failure
		Thread::wait(5000);
		SoftReset();
	}

	char tryNum = 5;
	char dtlsRetryAuthFlag = 0;
	ServerRequestCommand command = SERVER_REQUEST_UNDEFINED_COMMAND;

	// report the device status until
	while (true) {
		if (upgradeCancelFlag2 && step!=DEVICE_UPDATE_IDELING) {
			upgradeCancelFlag2 = false;
			memset(header.userUpdateFileInfo, 0, sizeof(header.userUpdateFileInfo));
			userFirmwareSendCompleteFlag = 1;
		}
		switch (step) {
			case DEVICE_UPDATE_IDELING:
				// start the device status report
				tryNum = 5;
				do {
					ret = deviceStatusReport(sockfd, 1);
					if (ret) {
						Thread::wait(3000);
					}
				} while(ret && tryNum--);
				if (ret == 0) {
					dtlsRetryAuthFlag = 0;
					// check the command identify
					if (serverRequestCommandFlag == 1) {
						serverRequestCommandFlag = 0;
						// check the receive command identify
						command = parseServerRequestCommand(serverRequestCommand);
						switch(command) {
							case SERVER_REQUEST_UPDATE_COMMAND:
								printf("%s : Update Command is detected......\n", __func__);
								step = DEVICE_UPDATE_COMMAND;
								break;
							case SERVER_REQUEST_EVAL_COMMAND:
								printf("%s : Eval Command is detected......\n", __func__);
								step = DEVICE_RESPONSE_EVAL_COMMAND;
								break;
							case SERVER_REQUEST_RANDOM_COMMAND:
								printf("%s : Random Command is detected......\n", __func__);
								step = DEVICE_RESPONSE_STR_RESULT_COMMAND;
								break;
							case SERVER_REQUEST_ITEMA_COMMAND:
							case SERVER_REQUEST_ITEMB_COMMAND:
							case SERVER_REQUEST_ITEMC_COMMAND:
							case SERVER_REQUEST_ITEMD_COMMAND:
							case SERVER_REQUEST_ITEME_COMMAND:
							case SERVER_REQUEST_ITEMF_COMMAND:
							case SERVER_REQUEST_CONFIGS_COMMAND:
							case SERVER_REQUEST_SCANPORTS_COMMAND:
								printf("%s : Log, Configs or Status Command is detected......\n", __func__);
								step = DEVICE_RESPONSE_BIN_RESULT_COMMAND;
								break;
							default:
								step = DEVICE_UPDATE_IDELING;
								break;
						}
						continue;
					}
				} else
					dtlsRetryAuthFlag = 1;
				break;
			case DEVICE_UPDATE_COMMAND:
				// check the device update information
				tryNum = 3;
				do {
					ret = deviceGetUpdateinfo(sockfd);
					if (ret) {
						Thread::wait(3000);
					}
				} while(ret && --tryNum);
				if (ret == 0) {
					dtlsRetryAuthFlag = 0;
					char ch = 2;
					queue.put(&ch);
					if (updateinfo.type == 1)
						step = USER_DEVICE_UPDATE_ONGOING;
					else if (updateinfo.type == 0)
						step = MYSELF_DEVICE_UPDATE_ONGOING;
					continue;
				} else {
					dtlsRetryAuthFlag = 1;
					step = DEVICE_UPDATE_IDELING;
				}
				break;
			case USER_DEVICE_UPDATE_ONGOING:
				upgradeCancelFlag2 = false;
				userFirmwareSendCompleteFlag = 0;
				tryNum = 5;
				do {
					ret = deviceGetSaveUpdatefile(sockfd);
					if (ret) {
						Thread::wait(3000);
					}
				} while (ret && tryNum--);
				if (ret == 0) {
					dtlsRetryAuthFlag = 0;
					char ch = 1;
					queue.put(&ch);
					step = USER_DEVICE_UPDATE_COMPLETE;
					continue;
				} else {
					// deviceGetSaveUpdatefile failure
					Thread::wait(3000);
					dtlsRetryAuthFlag = 1;
				}
				break;
			case USER_DEVICE_UPDATE_COMPLETE:
				// start the device status report
				tryNum = 5;
				do {
					ret = deviceStatusReport(sockfd, 3);
					if (ret) {
						Thread::wait(3000);
					}
				} while (ret && tryNum--);
				if (userFirmwareSendCompleteFlag == 1) {
					userFirmwareSendCompleteFlag = 0;
					deviceRegister(sockfd, 1);
					step = DEVICE_UPDATE_IDELING;
				}
				if (ret == 0) {
					dtlsRetryAuthFlag = 0;
				} else
					dtlsRetryAuthFlag = 1;

				break;
			case MYSELF_DEVICE_UPDATE_ONGOING:
			case MYSELF_DEVICE_ROLLBACK_COMPLETE:
				step = DEVICE_UPDATE_IDELING;
				break;
			case DEVICE_RESPONSE_STR_RESULT_COMMAND:
				tryNum = 3;
				do {
					ret = deviceResponseStringResultCommand(sockfd, command, NULL);
					if (ret) {
						Thread::wait(2000);
					}
				} while(ret && tryNum--);
				if (ret == 0) {
					dtlsRetryAuthFlag = 0;
				} else
					dtlsRetryAuthFlag = 1;
				step = DEVICE_UPDATE_IDELING;
				break;
			case DEVICE_RESPONSE_BIN_RESULT_COMMAND:
				tryNum = 3;
				do {
					ret = deviceResponseBinaryResultCommand(sockfd, command);
					if (ret) {
						Thread::wait(2000);
					}
				} while(ret && tryNum--);
				if (ret == 0) {
					dtlsRetryAuthFlag = 0;
				} else
					dtlsRetryAuthFlag = 1;
				step = DEVICE_UPDATE_IDELING;
				break;
			case DEVICE_RESPONSE_EVAL_COMMAND:
				tryNum = 3;
				do {
					ret = deviceResponseEvalCommand(sockfd);
					if (ret) {
						Thread::wait(2000);
					}
				} while(ret && tryNum--);
				if (ret == 0) {
					dtlsRetryAuthFlag = 0;
				} else
					dtlsRetryAuthFlag = 1;
				step = DEVICE_UPDATE_IDELING;
				break;
			default:
				step = DEVICE_UPDATE_IDELING;
				break;
		}
		Thread::wait(5000);

		if (dtlsRetryAuthFlag == 1) {
			int tryNum = 3;
			printf("\rRecive the sockfd timeout, retry to connect the peer...");
			dtls_free_context(dtls_context);
			do {
				ret = tinydtls_init(&sockfd);
				if (ret == -4)		//select timeout three times, break to restart the device
					break;
				else if (ret){
					printf("\rRetry to connect the peer failure, please wait or restart the device...");
					Thread::wait(3000);
				}
			} while(ret && tryNum--);
			if (ret) {
				printf("\rRetry to connect the peer failure, will restart the device...");
				SoftReset();
			}
		}
	}

	return ;
}
